﻿// 
//    Copyright 2010 The JaernCloud Project
// 
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
// 
//        http://www.apache.org/licenses/LICENSE-2.0
// 
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JaernCloud.Language.Compiler.Ast;

namespace JaernCloud.Language.Compiler.Types.Builtin {
    
    public class QueryNodeType : IQueryNodeType {
        private INodeType _parent;
        private List<INodeType> _blank = new List<INodeType>(0);
        private List<string> _names = new List<string>(1);
        private string _name;
        private AstNode _sourceNode;
        private INodeType _owner;
        private INodeType _queryOperatorType;

        public QueryNodeType(INodeType owner) {
            this._owner = owner;
            this.SourceNode = owner.SourceNode;
            var queryIdentifier = SourceNode.Query.Identifier;
            if (!String.IsNullOrEmpty(queryIdentifier)) {
                Name = queryIdentifier;
            }
        }

        public INodeType GetNodeTypeInstanceFor(AstNode node) {
            throw new NotSupportedException("");
        }

        public INodeType Owner {
            get {
                return _owner;
            }
            set { _owner = value; }
        }

        public AstQueryOperator QueryOperator {
            get { return SourceNode.Query; }
        }

        public INodeType QueryOperatorType {
            get {
                if (_queryOperatorType == null) {
                    AstForeachQueryOperator foreachQuery = QueryOperator as AstForeachQueryOperator;
                    if (foreachQuery != null) {
                        _queryOperatorType = NodeTypeGenerator.GetNodeTypeInstanceFor(foreachQuery.Node);
                    }
                    AstIfQueryOperator ifQuery = QueryOperator as AstIfQueryOperator;
                    if (ifQuery != null) {
                        _queryOperatorType = NodeTypeGenerator.GetNodeTypeInstanceFor(ifQuery.Node);
                    }
                    if (QueryOperator != null && _queryOperatorType == null) {
                        throw new NotSupportedException(QueryOperator + " is not supported");
                    }
                }
                return _queryOperatorType;
            }
        }

        public AstExpression QueryExpression {
            get {
                AstForeachQueryOperator foreachQuery = QueryOperator as AstForeachQueryOperator;
                if (foreachQuery != null) {
                    return foreachQuery.Expression;
                }
                AstIfQueryOperator ifQuery = QueryOperator as AstIfQueryOperator;
                if (ifQuery != null) {
                    return ifQuery.Expression;
                }
                throw new NotSupportedException(QueryOperator + " is not supported");
            }
        }

        public AstTag QueryTag {
            get {
                AstForeachQueryOperator query = QueryOperator as AstForeachQueryOperator;
                if (query != null) {
                    return query.Tag;
                }
                throw new NotSupportedException(QueryOperator + " is not supported");
            }
        }

        public QueryKind QueryKind {
            get {
                AstForeachQueryOperator foreachQuery = QueryOperator as AstForeachQueryOperator;
                if (foreachQuery != null) {
                    if (foreachQuery.Node.Children.Count > 0) {
                        return QueryKind.ByExample;
                    }
                    if (foreachQuery.Expression != null) {
                        return QueryKind.Expression;
                    }
                    if (foreachQuery.Tag != null && !string.IsNullOrEmpty(foreachQuery.Tag.Id)) {
                        return QueryKind.TagWithId;
                    }

                }
                AstIfQueryOperator ifQuery = QueryOperator as AstIfQueryOperator;
                if (ifQuery != null) {
                    return QueryKind.Expression;
                }
                throw new NotSupportedException(QueryOperator + " is not supported");
            }
        }


        #region IQueryProvider Members

        public IQueryable<TElement> CreateQuery<TElement>(System.Linq.Expressions.Expression expression) {
            throw new NotImplementedException();
        }

        public IQueryable CreateQuery(System.Linq.Expressions.Expression expression) {
            throw new NotImplementedException();
        }

        public TResult Execute<TResult>(System.Linq.Expressions.Expression expression) {
            throw new NotImplementedException();
        }

        public object Execute(System.Linq.Expressions.Expression expression) {
            throw new NotImplementedException();
        }

        #endregion

        #region INodeType Members

        public string Name {
            get { return _name; }
            set {
                _name = value;
                _names.Clear();
                _names.Add(value);
            }
        }

        public List<string> Names {
            get { return _names; }
        }

        public List<INodeType> Children {
            get { return _blank; }
        }

        public List<INodeType> InheritsFrom {
            get { return _blank; }
        }

        public INodeType Parent {
            get {
                return _parent;
            }
            set {
                _parent = value;
            }
        }

        public AstNode SourceNode {
            get { return _sourceNode; }
            set { _sourceNode = value; }
        }

        #endregion

        #region IEquatable<INodeType> Members

        public bool Equals(INodeType other) {
            return other == this;
        }

        #endregion

        public override string ToString() {
            return SourceNode.Query.ToString();
        }

    }
}
